package com.ikingtech.platform.business.message.service.router;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ikingtech.framework.sdk.enums.message.MessageChannelContentTypeEnum;
import com.ikingtech.framework.sdk.enums.message.MessageChannelStatusEnum;
import com.ikingtech.framework.sdk.enums.message.MessageSendChannelEnum;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.platform.business.message.entity.MessageChannelDefinitionDO;
import com.ikingtech.platform.business.message.service.repository.MessageChannelDefinitionRepository;
import com.ikingtech.platform.service.push.common.DeliverResult;
import com.ikingtech.platform.service.push.common.MessageBody;
import com.ikingtech.platform.service.push.common.MessageRedirect;
import com.ikingtech.platform.service.push.common.PushRequest;
import lombok.RequiredArgsConstructor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.ikingtech.framework.sdk.utils.Tools.Str.CONTENT_PLACEHOLDER_PREFIX;
import static com.ikingtech.framework.sdk.utils.Tools.Str.CONTENT_PLACEHOLDER_SUFFIX;

/**
 * @author tie yan
 */
@RequiredArgsConstructor
public abstract class AbstractMessageRouter implements MessageRouter {

    protected final MessageChannelDefinitionRepository channelDefinitionRepo;

    @Override
    public RouteResult route(RouteRequest request) {
        MessageChannelDefinitionDO channelDefinitionEntity = this.channelDefinitionRepo.getOne(Wrappers.<MessageChannelDefinitionDO>lambdaQuery()
                .eq(MessageChannelDefinitionDO::getTemplateId, request.getTemplateId())
                .eq(MessageChannelDefinitionDO::getChannel, this.channel().name()));
        PushRequest pushRequest = this.parseBody(request, channelDefinitionEntity);
        if (!MessageChannelStatusEnum.ENABLED.name().equals(channelDefinitionEntity.getStatus())) {
            return new RouteResult(pushRequest.getBody().getText(),
                    Tools.Coll.convertList(pushRequest.getBody().getRedirectTo(), MessageRedirect::getRedirectLink),
                    false,
                    "消息渠道未启用",
                    pushRequest.getBody().getBusinessName(),
                    pushRequest.getBody().getMessageTitle());
        }
        DeliverResult result = this.send(pushRequest, request);
        return new RouteResult(pushRequest.getBody().getText(),
                Tools.Coll.convertList(pushRequest.getBody().getRedirectTo(), MessageRedirect::getRedirectLink),
                result.getSuccess(),
                result.getCause(),
                pushRequest.getBody().getBusinessName(),
                pushRequest.getBody().getMessageTitle());
    }

    @Override
    public abstract MessageSendChannelEnum channel();

    protected PushRequest parseBody(RouteRequest request, MessageChannelDefinitionDO channelDefinitionEntity) {
        Map<String, Object> messageParamMap = Tools.Json.objToMap(request.getMessageWrapper());
        PushRequest pushRequest = new PushRequest();
        MessageBody body = new MessageBody();
        pushRequest.setAppConfigId(channelDefinitionEntity.getChannelId());
        if (Boolean.TRUE.equals(channelDefinitionEntity.getSupportTemplate())) {
            pushRequest.setTemplateId(channelDefinitionEntity.getChannelTemplateId());
            if (Tools.Coll.isNotBlankMap(messageParamMap)) {
                pushRequest.setTemplateParams(this.convertToTemplateParam(request.getParamDefinitionMap(), messageParamMap));
            }
        }
        body.setText(this.parseBodyText(request, channelDefinitionEntity, messageParamMap));
        body.setBusinessName(channelDefinitionEntity.getBusinessName());
        body.setBusinessKey(channelDefinitionEntity.getBusinessKey());
        body.setMessageTitle(Tools.Str.replace(channelDefinitionEntity.getMessageTitle(), CONTENT_PLACEHOLDER_PREFIX, CONTENT_PLACEHOLDER_SUFFIX, messageParamMap));
        body.setShowNotification(channelDefinitionEntity.getShowNotification());
        Boolean ignoreRedirect = (Boolean) messageParamMap.get("ignoreRedirect");
        if (!Boolean.TRUE.equals(ignoreRedirect)) {
            body.setRedirectTo(this.createMessageRedirect(request.getRedirectDefinitinoMap(), messageParamMap));
        }
        pushRequest.setBody(body);
        return pushRequest;
    }

    protected String parseBodyText(RouteRequest request, MessageChannelDefinitionDO channelDefinitionEntity, Map<String, Object> messageParamMap) {
        if (MessageChannelContentTypeEnum.SELF.name().equals(channelDefinitionEntity.getContentType())) {
            return this.convertToTemplateContent(messageParamMap, channelDefinitionEntity.getContent());
        }
        if (MessageChannelContentTypeEnum.CUSTOMIZE.name().equals(channelDefinitionEntity.getContentType())) {
            return this.convertToTemplateContent(messageParamMap, channelDefinitionEntity.getCustomizeContent());
        }
        if (MessageChannelContentTypeEnum.SYSTEM.name().equals(channelDefinitionEntity.getContentType())) {
            MessageChannelDefinitionDO systemChannelDefinitionEntity = this.channelDefinitionRepo.getOne(Wrappers.<MessageChannelDefinitionDO>lambdaQuery()
                    .eq(MessageChannelDefinitionDO::getTemplateId, channelDefinitionEntity.getTemplateId())
                    .eq(MessageChannelDefinitionDO::getChannel, MessageSendChannelEnum.SYSTEM.name()));
            return this.convertToTemplateContent(messageParamMap, systemChannelDefinitionEntity.getContent());
        }
        return Tools.Str.EMPTY;
    }

    protected abstract DeliverResult send(PushRequest pushRequest, RouteRequest request);

    protected List<MessageRedirect> createMessageRedirect(Map<String, String> redirects, Map<String, Object> messageParamMap) {
        List<MessageRedirect> result = new ArrayList<>();
        redirects.forEach((redirectName, redirectLink) -> {
            MessageRedirect redirect = new MessageRedirect();
            redirect.setRedirectLink(Tools.Str.replace(redirectLink, CONTENT_PLACEHOLDER_PREFIX, CONTENT_PLACEHOLDER_SUFFIX, messageParamMap));
            redirect.setRedirectName(redirectName);
            result.add(redirect);
        });
        return result;
    }

    protected String convertToTemplateContent(Map<String, Object> messageParamMap, String templateContent) {
        if (Tools.Coll.isBlankMap(messageParamMap) ||
                !templateContent.contains(CONTENT_PLACEHOLDER_PREFIX)) {
            return templateContent;
        } else {
            return Tools.Str.replace(templateContent, CONTENT_PLACEHOLDER_PREFIX, CONTENT_PLACEHOLDER_SUFFIX, messageParamMap);
        }
    }

    protected Map<String, Object> convertToTemplateParam(Map<String, String> paramDefinitions, Map<String, Object> messageParamMap) {
        Map<String, Object> templateParams = new HashMap<>();
        paramDefinitions.forEach((param, mappedParam) -> templateParams.put(mappedParam, messageParamMap.get(param)));
        return templateParams;
    }
}
